﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace Master
{
    class ThreeLaneTrafficLightStrategy : iTrafficLightStrategy
    {
        /*************
        * VARIABLES *
        *************/
        private Thread strategyThread;
        private List<Lane> lanes;

        /********************
         * PUBLIC FUNCTIONS *
         ********************/
        public void start(Dictionary<Side, List<Road>> roadDictionary)
        {
            lanes = new List<Lane>();
            foreach (List<Road> sublist in roadDictionary.Values)
                foreach (Road road in sublist)
                    foreach (Lane lane in road.getLanes())
                        if (lane.hasTrafficLight())
                            lanes.Add(lane);
            strategyThread = new Thread(handleTraffic);
            strategyThread.Start();
        }

        public void stop()
        {
            strategyThread.Abort();
        }

        /*********************
         * PRIVATE FUNCTIONS *
         *********************/

        private List<Lane> getCurrentLanes(Boolean horizontal, Boolean leftTurn)
        {
            List<Lane> currentLanes = new List<Lane>();
            foreach (Lane lane in lanes)
            {
                int orientation = 0;
                int direction = 0;
                lane.trafficLight.Dispatcher.Invoke(new Action(delegate() { orientation = lane.Orientation; direction = lane.AllowedDirections; }));
                Boolean horizontalLanes = horizontalOrientation(horizontal, orientation);
                Boolean turnLeftLanes = turnLeft(leftTurn, direction);
                // Looks if horizontal or vertical lanes should be put on green and if the traficlights to turn left or to go forward and turn right should go on green.
                if (    (horizontal == true && horizontalLanes == true && leftTurn == false && turnLeftLanes == false)
                    || ((horizontal == true && horizontalLanes == true && leftTurn == true && turnLeftLanes == true) || (leftTurn == true && direction == 2 && horizontalLanes == false)) 
                    ||  (horizontal == false && horizontalLanes == false && leftTurn == false && turnLeftLanes == false)
                    || ((horizontal == false && horizontalLanes == false && leftTurn == true && turnLeftLanes == true) || (leftTurn == true && direction == 2 && horizontalLanes == true))
                    )
                    currentLanes.Add(lane);
            }
            return currentLanes;
        }
        private Boolean horizontalOrientation(Boolean horizontal, int orientation) 
        {
            if (orientation == 0 || orientation == 180)
                return true;
            return false;
        }
        private Boolean turnLeft(Boolean leftTurn, int direction) 
        {
            if (direction == 1)
                return true;
            return false;
        }
        private void setStatus(List<Lane> currentLanes, TrafficLightStatus newStatus, int sleepTime)
        {
            foreach (Lane lane in currentLanes)
                lane.Dispatcher.Invoke(
                        new Action(delegate() { lane.trafficLight.SetValue(TrafficLight.statusProperty, newStatus); })
                        );
            Thread.Sleep(sleepTime);
        }

        private void handleTraffic()
        {
            try
            {
                Boolean horizontal = true, turnLeft = false;
                
                while (true)
                {
                    List<Lane> currentLanes = getCurrentLanes(horizontal, turnLeft);
                    setStatus(currentLanes, TrafficLightStatus.GREEN, 7500);
                    setStatus(currentLanes, TrafficLightStatus.ORANGE, 5000);
                    setStatus(currentLanes, TrafficLightStatus.RED, 500);
                    if(turnLeft == true)
                        horizontal = !horizontal;
                    turnLeft = !turnLeft;

                }
            }
            catch (ThreadAbortException e)
            {
                Trace.WriteLine("Thread was aborted by: " + e.GetType());
                return;
            }
        }
    }
}
